package io.mvvm.ws.handler;

import com.alibaba.fastjson.JSON;
import io.mvvm.common.constant.SystemConstants;
import io.mvvm.security.utils.JwtUtil;
import io.mvvm.utils.RedisUtil;
import io.mvvm.ws.WebSocketChannelHolder;
import io.mvvm.ws.entity.RequestInfo;
import io.mvvm.ws.entity.ResponseInfo;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.util.Attribute;
import io.netty.util.AttributeKey;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.Map;

/**
 * @program: Netty
 * @description: 鉴权处理器
 * @author: 潘
 * @create: 2021-04-28 22:24
 **/
@Component
@ChannelHandler.Sharable
public class WebSocketAuthHandler extends ChannelInboundHandlerAdapter {

    @Resource
    private RedisUtil redisUtil;

    public static final String HANDLER_NAME = "WebSocketAuthHandler";

    private static Logger logger = LoggerFactory.getLogger(WebSocketAuthHandler.class);

    public static AttributeKey<String> key = AttributeKey.valueOf("userId");

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object obj) throws Exception {
        if (null == obj) {
            return;
        }
        RequestInfo msg = (RequestInfo) obj;
        Map<String, Object> params = msg.getParams();
        String token = (String) params.get("token");

        // 如果鉴权失败，则关闭通道
        if (!checkToken(token, msg)) {
            logger.warn("鉴权未通过");
            ctx.channel().close();
            return;
        }
        ctx.channel().attr(key).set(msg.getUserId());

        // 热拔插鉴权处理器，如果鉴权通过了就不需要此处理器
        ctx.pipeline().remove(HANDLER_NAME);
        logger.info("授权通过");
        super.channelRead(ctx, msg);
    }


    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
        logger.warn("通道 [ {} ] 删除处理器 [{}]", ctx.channel().id().asShortText(), this);
        super.handlerRemoved(ctx);
    }

    private boolean checkToken(String token, RequestInfo msg) {
        if (null == token || token.split("\\.").length != 3) {
            return false;
        }
        String username = JwtUtil.parseToken(token, "_secret");
        String loginStatusBack = SystemConstants.append(SystemConstants.LOGIN_STATUS, username);
        String redisToken = (String) redisUtil.get(loginStatusBack);
        msg.setUserId(username);
        return redisToken.equals(token);
    }

}
